using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using Game500.ClientServerCommon.Src;

namespace MtServer.Src
{
  public class ServerFrontend
  {
    private readonly Dictionary<Guid, NetworkGameInfo> myActiveGames = new Dictionary<Guid, NetworkGameInfo>();
    private readonly IPAddress myAddress;
    private readonly BaseMapManager myMapManager;
    private readonly int myPort;
    private readonly string myServerName;

    public ServerFrontend(int port, string serverName, IPAddress address, BaseMapManager mapManager)
    {
      myPort = port;
      myServerName = serverName;
      myAddress = address;
      myMapManager = mapManager;
    }

    private void ClientThread(object arg)
    {
      if (arg == null) throw new ArgumentNullException("arg");
      var client = arg as TcpClient;
      Debug.Assert(client != null, "Incorrect argument for Client Thread start");

      NetworkStream stream = client.GetStream();
      var formatter = new BinaryFormatter();
      var command = (FrontendRequest)formatter.Deserialize(stream);

      if (command.RequestType == FrontendRequest.RequestTypeEnum.GetInfo)
      {
        var info = new FrontendInfo(myServerName, myMapManager.GetAvailableMapIds().ToList(), myActiveGames.Select(x => x.Value).ToList());
        formatter.Serialize(stream, info);
      }
      else if (command.RequestType == FrontendRequest.RequestTypeEnum.CreateGame)
      {
        var serverThread = new SessionThread(command.MapId, command.GameMessage, myMapManager, myAddress);
        NetworkGameInfo info = serverThread.GameInfo;
        serverThread.Initialize(() => { lock (myActiveGames) myActiveGames.Add(info.GameId, info); },
                                () => { lock (myActiveGames) myActiveGames.Remove(info.GameId); });
        formatter.Serialize(stream, info);
      }

      client.Close();
    }

    public void Start()
    {
      var listener = new TcpListener(IPAddress.Any, myPort);
      listener.Start();
      while (true)
      {
        TcpClient client = listener.AcceptTcpClient();
        var thread = new Thread(ClientThread);
        thread.Name = "ListenerThread";
        thread.Start(client);
      }
// ReSharper disable FunctionNeverReturns
    }

// ReSharper restore FunctionNeverReturns
  }
}